Skip to content

Feat: add mithril-client CLI command for UTxO-HD ledger state snapshot conversion #2518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

dlachaume
Copy link
Collaborator

Content

This PR includes...

Pre-submit checklist

  • Branch
    • Tests are provided (if possible)
    • Crates versions are updated (if relevant)
    • CHANGELOG file is updated (if relevant)
    • Commit sequence broadly makes sense
    • Key commits have useful messages
  • PR
    • All check jobs of the CI have succeeded
    • Self-reviewed the diff
    • Useful pull request description
    • Reviewer requested
  • Documentation
    • Update README file (if relevant)
    • Update documentation website (if relevant)
    • Add dev blog post (if relevant)
    • Add ADR blog post or Dev ADR entry (if relevant)
    • No new TODOs introduced

Comments

Issue(s)

Closes #2492

@dlachaume dlachaume self-assigned this May 23, 2025
Copy link

Test Results

    3 files  ± 0     77 suites  ±0   14m 40s ⏱️ - 1m 14s
1 948 tests +17  1 948 ✅ +17  0 💤 ±0  0 ❌ ±0 
3 329 runs  +51  3 329 ✅ +51  0 💤 ±0  0 ❌ ±0 

Results for commit cc19034. ± Comparison against base commit 623dbe8.

@dlachaume dlachaume temporarily deployed to testing-preview May 23, 2025 16:27 — with GitHub Actions Inactive
/// Trait for interacting with the GitHub API to retrieve Cardano node release.
#[cfg_attr(test, mockall::automock)]
#[async_trait]
pub trait GitHubApiClient {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you need a trait for a GitHub API Client, you should do the following:

  • rename the module to github_release_retriever.rs
  • rename the trait to GitHubReleaserRetriever (and put it in an interface.rs sub-module?)
  • move the GitHubRelease in the module
  • rename the reqwest_github_api_client.rs sub-module to reqwest.rs

Comment on lines +36 to +48
let url = Url::parse(&url)
.with_context(|| format!("Failed to parse URL for GitHub API: {}", url))?;

let response = self
.client
.get(url.clone())
.send()
.await
.with_context(|| format!("Failed to send request to GitHub API: {}", url))?;

let response = response.text().await?;
let release: GitHubRelease = serde_json::from_str(&response)
.with_context(|| format!("Failed to parse response from GitHub API: {:?}", response))?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code can be refactored in a function that retrieves the content from a URL and deserialize it into a generic type.
This download function could even be part of the HttpDownloader trait (by renaming the existing download function to download_file).

}

impl GitHubRelease {
pub fn is_prerelease(&self) -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is probably interesting only if the visibility of the prerelease field is not public.

Comment on lines +70 to +75
fn dummy_linux_asset() -> GitHubAsset {
GitHubAsset {
name: format!("asset-name-{}.tar.gz", ASSET_PLATFORM_LINUX),
browser_download_url: "https://release-assets.com/linux".to_string(),
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can have only one function fn dummy_asset(os: &str) -> GitHubAsset here.

fs2 = "0.4.3"
futures = "0.3.31"
human_bytes = { version = "0.4.3", features = ["fast"] }
indicatif = { version = "0.17.11", features = ["tokio"] }
mithril-cli-helper = { path = "../internal/mithril-cli-helper" }
mithril-client = { path = "../mithril-client", features = ["fs", "unstable"] }
mithril-doc = { path = "../internal/mithril-doc" }
reqwest = { workspace = true }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workspace only specify the minimal set of shared features for reqwest since we don't want to force them on downstream library users.
For our binaries we needs a bit more:

Suggested change
reqwest = { workspace = true }
reqwest = { workspace = true, features = [
"default",
"gzip",
"zstd",
"deflate",
"brotli"
] }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should keep the commands module focused and move all utilities to the utils module (archive unpacker, github api client, http downloader).

Comment on lines +92 to +100
let root_file = temp_dir.join("root.txt");
assert!(root_file.exists());
let root_file_content = fs::read_to_string(root_file).unwrap();
assert_eq!(root_file_content, "root content");

let nested_file = temp_dir.join("nested/dir/nested-file.txt");
assert!(nested_file.exists());
let nested_file_content = fs::read_to_string(nested_file).unwrap();
assert_eq!(nested_file_content, "nested content");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: You could use assert_dir_eq for the existence check.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any value to return a ArchiveUnpacker instance to this api users ? It seems to exist only to enable testing.

It would refactor a bit this part:

  • Rename ArchiveUnpacker trait to ArchiveFormat with two methods: the actual unpack method and a support(&path) -> bool method
  • Rename ArchiveUnpackerSelector to ArchiveUnpacker:
    • with two methods: a public unpack(&path) -> Result<()> method and a private select_unpacker method
    • It would contains a list of ArchiveFormat impl and a Default impl that would manually add the two known format to this list.
    • select_unpacker would iterate over its format list and return the first unpacker which support the given archive
    • unpack would simply call select_unpacker then do the unpacking.

Comment on lines +79 to +87
let root_file = temp_dir.join("root.txt");
assert!(root_file.exists());
let root_file_content = fs::read_to_string(&root_file).unwrap();
assert_eq!(root_file_content, "root content");

let nested_file = temp_dir.join("nested/dir/nested-file.txt");
assert!(nested_file.exists());
let nested_file_content = fs::read_to_string(&nested_file).unwrap();
assert_eq!(nested_file_content, "nested content");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: You could use assert_dir_eq for the existence check.

const LEDGER_DIR: &str = "ledger";

#[derive(Debug, Clone, ValueEnum)]
enum UTxOHDFlavor {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to support lower case (and maybe only lower case) here ?

/// Main command execution
pub async fn execute(&self) -> MithrilResult<()> {
let distribution_temp_dir = self.db_directory.join(CARDANO_DISTRIBUTION_TEMP_DIR);
std::fs::create_dir(distribution_temp_dir.clone()).with_context(|| {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most fs methods takes AsRef<Path> as input which accept both moving the provided value or passing it by reference.

Suggested change
std::fs::create_dir(distribution_temp_dir.clone()).with_context(|| {
std::fs::create_dir(&distribution_temp_dir).with_context(|| {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a Mithril client CLI command for UTxO-HD ledger state snapshot conversion
3 participants